#include <stdio.h>
#include <stdarg.h>
#include <sys/time.h>
#include <unistd.h>
#include <malloc.h>
#include <stdlib.h>
#include <string.h>

#include <icommon.h>
#ifdef DMALLOC
#include <imp/dmalloc.h>
#endif
void c_log_default(const char *module, int i_level, const char *psz_fmt, va_list arg)
{
    char *psz_prefix;

    switch(i_level) {
	case C_LOG_ERROR:
		psz_prefix = "error";
		break;
    case C_LOG_WARNING:
		psz_prefix = "warning";
		break;
    case C_LOG_INFO:
		psz_prefix = "info";
		break;
	case C_LOG_DEBUG:
		psz_prefix = "debug";
		break;
	default:
		psz_prefix = "unknown";
		break;
    }

    fprintf(stderr, "%s[%s]: ", module, psz_prefix);
    vfprintf(stderr, psz_fmt, arg);
}

void c_log(int i_level, const char *psz_fmt, ... )
{
    if(i_level <= C_LOG_INFO) {
        va_list arg;
        va_start( arg, psz_fmt );
		c_log_default("icommon", i_level, psz_fmt, arg);
        va_end(arg);
    }
}

int64_t c_mdate(void)
{
    struct timeval tv_date;
    gettimeofday( &tv_date, NULL );

    return (int64_t)tv_date.tv_sec * 1000000 + (int64_t)tv_date.tv_usec;
}

void *c_malloc(int index, int size, int align)
{
	void *addr = NULL;
	int pagesize = -1;

	pagesize = getpagesize();

	if (align > pagesize) {
		c_log(C_LOG_ERROR, "align over pagesize:%d\n", pagesize);
		goto err_align_over_pagesize;
	}


	if ((addr = memalign(align, size)) == NULL) {
		c_log(C_LOG_ERROR, "memalign size:%d (aligned %d) failed\n", size, align);
		goto err_memalign;
	}

	return addr;

err_memalign:
err_align_over_pagesize:
	return NULL;
}

void *c_malloc_check_zero(int size, int align, const char *format, ...)
{
    void *ptr = c_malloc(-1, size, align);
    if (ptr == NULL) {
        va_list arg;
        va_start(arg, format);
		c_log_default("icommon", C_LOG_ERROR, format, arg);
        va_end(arg);
        abort();
    }
    memset(ptr, 0, sizeof(size));

    return ptr;
}

void c_free(int index, void *addr)
{
	if (addr) {
		free(addr);
	}
}

intptr_t c_virt_to_phys(intptr_t vaddr)
{
	return vaddr;
}

intptr_t c_phys_to_virt(intptr_t paddr)
{
	return paddr;
}

int c_align(int x, int align, int disalign)
{
    x = C_ALIGN(x, align);
#if 0
    if(!(x&(disalign-1)))
        x += C_VB_ALIGN;
#endif
    return x;
}

inline int c_clip3(int v, int i_min, int i_max)
{
    return ((v < i_min) ? i_min : ((v > i_max) ? i_max : v));
}

inline double c_clip3f(double v, double f_min, double f_max)
{
    return ((v < f_min) ? f_min : ((v > f_max) ? f_max : v));
}

inline int c_median(int a, int b, int c)
{
    int t = (a-b)&((a-b)>>31);
    a -= t;
    b += t;
    b -= (b-c)&((b-c)>>31);
    b += (a-b)&((a-b)>>31);

    return b;
}

REDUCE_FRACTION(c_reduce_fraction  , uint32_t)
REDUCE_FRACTION(c_reduce_fraction64, uint64_t)
